All files / web/src/app/practice/[studentId]/observe page.tsx

0% Statements 0/115
0% Branches 0/1
0% Functions 0/1
0% Lines 0/115

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                                                                                                                                                                                                                                       
import { notFound, redirect } from 'next/navigation'
import { getPlayerAccess, isParentOf } from '@/lib/classroom'
import { getActiveSessionPlan, getPracticeStudent } from '@/lib/curriculum/server'
import type { ActiveSessionInfo } from '@/hooks/useClassroom'
import { getUserId } from '@/lib/viewer'
import { ObservationClient } from './ObservationClient'
import { StudentNotPresentPage } from './StudentNotPresentPage'

export const dynamic = 'force-dynamic'

interface ObservationPageProps {
  params: Promise<{ studentId: string }>
}

export default async function PracticeObservationPage({ params }: ObservationPageProps) {
  const { studentId } = await params
  const [observerId, player, activeSession] = await Promise.all([
    getUserId(),
    getPracticeStudent(studentId),
    getActiveSessionPlan(studentId),
  ])

  if (!player) {
    notFound()
  }

  const [access, isParent] = await Promise.all([
    getPlayerAccess(observerId, studentId),
    isParentOf(observerId, studentId),
  ])

  // Check if user can observe (parent or teacher-present)
  const canObserve = access.isParent || access.isPresent

  if (!canObserve) {
    // If they're a teacher but student isn't present, show helpful message
    if (access.isTeacher && access.classroomId) {
      return (
        <StudentNotPresentPage
          studentName={player.name}
          studentEmoji={player.emoji}
          studentId={studentId}
          classroomId={access.classroomId}
        />
      )
    }
    // Otherwise, they have no relationship to this student
    notFound()
  }

  // If session is completed, show the observation page with a banner linking to the report
  if (activeSession?.completedAt) {
    return (
      <ObservationClient
        session={{
          sessionId: activeSession.id,
          playerId: activeSession.playerId,
          startedAt: activeSession.startedAt!.toISOString(),
          currentPartIndex: activeSession.currentPartIndex,
          currentSlotIndex: activeSession.currentSlotIndex,
          totalParts: activeSession.parts.length,
          totalProblems: activeSession.parts.reduce((sum, part) => sum + part.slots.length, 0),
          completedProblems: activeSession.parts.reduce((sum, part) => sum + part.slots.length, 0),
        }}
        observerId={observerId}
        student={{
          name: player.name,
          emoji: player.emoji,
          color: player.color,
        }}
        studentId={studentId}
        isParent={isParent}
        sessionReportUrl={`/practice/${studentId}/session/${activeSession.id}`}
        sessionEnded
      />
    )
  }

  // If no active session or session hasn't started, go to dashboard
  if (!activeSession || !activeSession.startedAt) {
    redirect(`/practice/${studentId}/dashboard`)
  }

  const totalProblems = activeSession.parts.reduce((sum, part) => sum + part.slots.length, 0)
  let completedProblems = 0
  for (let i = 0; i < activeSession.currentPartIndex; i++) {
    completedProblems += activeSession.parts[i]?.slots.length ?? 0
  }
  completedProblems += activeSession.currentSlotIndex

  const session: ActiveSessionInfo = {
    sessionId: activeSession.id,
    playerId: activeSession.playerId,
    startedAt: activeSession.startedAt!.toISOString(),
    currentPartIndex: activeSession.currentPartIndex,
    currentSlotIndex: activeSession.currentSlotIndex,
    totalParts: activeSession.parts.length,
    totalProblems,
    completedProblems,
  }

  return (
    <ObservationClient
      session={session}
      observerId={observerId}
      student={{
        name: player.name,
        emoji: player.emoji,
        color: player.color,
      }}
      studentId={studentId}
      isParent={isParent}
    />
  )
}